package typedefault

import "C"
import (
	"codejy/globalfunc"
	"codejy/store"
	"codejy/structdef"
	"github.com/robfig/cron/v3"
	"os"
	"strconv"
	"strings"
	"sync"
)

type Timer struct {
	Addr        string
	ThreadStore *structdef.ThreadStore
	C           *cron.Cron
	Record      map[string]map[string]string
	status      bool
}

// 创建实例
func (a *Timer) CreateTypeDefault(addr string, threadStore *structdef.ThreadStore, parameter ...string) {
	//为了不让主线程退出
	group := globalfunc.ExecuteFunc("GetThreadAllWait").(*sync.WaitGroup)
	group.Add(1)
	instance := &Timer{
		Addr:        addr,
		ThreadStore: threadStore,
		C:           cron.New(cron.WithSeconds()),
		Record:      make(map[string]map[string]string),
		status:      true,
	}
	instance.C.Start() //启动定时器
	store.AddTypeDefaultInstanceStore(threadStore, a.GetTypeName(), addr, instance)
}
func (a *Timer) ParameterProcessing(parameter []string) []string {
	return parameter
}

func (a *Timer) GetData() interface{} {
	return nil
}

func (a *Timer) ToStr() string {
	return ""
}

// 添加定时任务
func (a *Timer) AddFunc(arguments string) string {
	funcArgs, b := GetTypeDefaultValue[[]string](a.ThreadStore, "List", arguments)
	if !b {
		panic("Timer-addFunc参数错误")
	}
	if len(funcArgs) < 2 {
		panic("错误::::::第一个参数不能为空,必须是cron表达式,第二个参数不能为空,必须是函数名称")
	}
	cronV := funcArgs[0] //cron
	//排除前后""
	if strings.HasPrefix(cronV, "\"") && strings.HasSuffix(cronV, "\"") {
		cronV = cronV[1 : len(cronV)-1]
	}

	funcName := funcArgs[1] //函数名称
	//排除前后""
	if strings.HasPrefix(funcName, "\"") && strings.HasSuffix(funcName, "\"") {
		funcName = funcName[1 : len(funcName)-1]
	}
	if len(funcArgs) > 2 {
		funcArgs = funcArgs[2:] //函数参数
	} else {
		funcArgs = []string{}
	}

	//获取函数定义,函数定义是在当前文件中定义的
	definition := store.SearchFunDefinition(a.ThreadStore, funcName)
	if definition == nil {
		panic("错误::::::函数未定义:" + funcName)
	}

	addFunc, err := a.C.AddFunc(cronV, func() {
		defer func() {
			if err1 := recover(); err1 != nil {
				store.PrintExecuteCodeRecordLog(a.ThreadStore, err1)
				os.Exit(1)
			}
		}()
		globalfunc.ExecuteFunc("FunLineExecute", a.ThreadStore, definition.Body, "", definition.Name, funcArgs)
	})
	if err != nil {
		panic(err)
	}
	itoa := strconv.Itoa(int(addFunc))
	_, P := a.Record[itoa]
	if P { //如果不存在则创建
		panic("错误::::::定时任务id已存在(定时器自己问题):" + itoa)
	}
	a.Record[itoa] = make(map[string]string)
	a.Record[itoa]["id"] = itoa
	a.Record[itoa]["cron"] = cronV
	a.Record[itoa]["funcName"] = funcName
	if len(funcArgs) > 2 {
		a.Record[itoa]["funcArgs"] = strings.Join(funcArgs[2:], ",")
	} else {
		a.Record[itoa]["funcArgs"] = ""
	}
	return itoa
}

// 移除定时任务
func (a *Timer) RemoveFunc(id string) {
	var v interface{}
	v = id
	a.C.Remove(v.(cron.EntryID))
}

// 获取定时任务id列表
func (a *Timer) Maps() string {
	var maps map[string]string
	for k, v := range a.Record {
		var addrMap = globalfunc.ExecuteFunc("MapToMap", v, a.ThreadStore).(string)
		maps[k] = addrMap
	}
	var addrMap = globalfunc.ExecuteFunc("MapToMap", maps, a.ThreadStore).(string)
	return addrMap
}

// 停止定时器
func (a *Timer) Stop() {
	a.C.Stop()
	if a.status {
		//因为定时器结束后,需要让主线程结束
		group := globalfunc.ExecuteFunc("GetThreadAllWait").(*sync.WaitGroup)
		group.Done()
		a.status = false
	}
}

// 启动定时器
func (a *Timer) Run() {
	a.C.Start()
	if a.status == false {
		//为了不让主线程退出
		group := globalfunc.ExecuteFunc("GetThreadAllWait").(*sync.WaitGroup)
		group.Add(1)
		a.status = true
	}
}

func (f *Timer) GetDef() string {
	return `
		@CodeManual(def="new("Timer")",des="创建定时器,并启动定时器")
		type Timer{
			def init{
				core&CreateTypeDefault()
			}
			@CodeManual(def="add(cron,funcName,funcArgs)",des="添加定时任务,返回定时任务id")
			def add{
				to core&AddFunc($realArgs)
			}
			@CodeManual(def="del(id)",des="移除定时任务")
			def del{
				core&RemoveFunc($1)
			}
			@CodeManual(def="maps()",des="获取定时任务id列表,返回的是map容器实例")
			def maps{
				core&Maps()
			}
			@CodeManual(def="stop()",des="停止定时器")
			def stop{
				core&Stop()
			}
			@CodeManual(def="run()",des="启动定时器,如果定时器已经启动,则不会启动")
			def run{
				core&Run()	
			}
		
		}
	`
}
func init() {
	RegisterTypeDefault(&Timer{})
}

func (f *Timer) GetTypeName() string {
	return "Timer"
}
